﻿using Kingdee.BOS;
using Kingdee.BOS.App;
using Kingdee.BOS.App.Data;
using Kingdee.BOS.Contracts;
using Kingdee.BOS.Core;
using Kingdee.BOS.Core.Bill;
using Kingdee.BOS.Core.BusinessFlow;
using Kingdee.BOS.Core.DynamicForm;
using Kingdee.BOS.Core.DynamicForm.Operation;
using Kingdee.BOS.Core.DynamicForm.PlugIn;
using Kingdee.BOS.Core.DynamicForm.PlugIn.Args;
using Kingdee.BOS.Core.Interaction;
using Kingdee.BOS.Core.List;
using Kingdee.BOS.Core.Metadata;
using Kingdee.BOS.Core.Metadata.ConvertElement;
using Kingdee.BOS.Core.Metadata.ConvertElement.ServiceArgs;
using Kingdee.BOS.Core.Metadata.EntityElement;
using Kingdee.BOS.Core.Metadata.FieldElement;
using Kingdee.BOS.Core.Metadata.FormElement;
using Kingdee.BOS.JSON;
using Kingdee.BOS.Log;
using Kingdee.BOS.Orm;
using Kingdee.BOS.Orm.DataEntity;
using Kingdee.BOS.ServiceFacade.KDServiceFx;
using Kingdee.BOS.ServiceHelper;
using Kingdee.BOS.Util;
using Kingdee.BOS.WebApi.Client;
using Kingdee.BOS.WebApi.ServicesStub;
using Kingdee.K3.FIN.App.Core;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace DzInfo.TuiLing.WebApi
{
    public class AutoReturnPicking : AbstractWebApiBusinessService
    {
        private List<int> ppbomentryIds = new List<int>();
        public AutoReturnPicking(KDServiceContext context) : base(context)
        {

        }
        public object AutoPicking(string parameter)
        {
            // 1. 参数验证
            if (string.IsNullOrEmpty(parameter))
            {
                return "请求参数不能为空";
            }

            // 2. 解析JSON参数
            JSONObject requestData;
            try
            {
                requestData = JSONObject.Parse(parameter) as JSONObject;
            }
            catch (Exception ex)
            {
                return $"JSON解析失败: {ex.Message}";
            }

            // 3. 直接使用整个请求数据作为参数节点，不再提取parameter子节点
            JSONObject parameterNode = requestData;
            // 4. 提取基础参数
            var userName = requestData["K3UserName"]?.ToString();
            var appsecret = requestData["K3AppSecret"]?.ToString();
            var appid = requestData["K3AppID"]?.ToString();
            var dbId = requestData["K3DBID"]?.ToString();
            string baseUrl = requestData["K3baseUrl"]?.ToString();
            HttpClient httpClient = new HttpClient();
            httpClient.Url = baseUrl + "Kingdee.BOS.WebApi.ServicesStub.AuthService.LoginByAppSecret.common.kdsvc";


            List<object> Parameters = new List<object>();
            Parameters.Add(dbId);//账套标示
            Parameters.Add(userName);//用户名
            //Parameters.Add("888888");//密码
            Parameters.Add(appid);//应用ID
            Parameters.Add(appsecret);//应用秘钥
            Parameters.Add(2052);//2052代表中文
            httpClient.Content = JsonConvert.SerializeObject(Parameters);

            var res = httpClient.SysncRequest();

            // 解析JSON
            JObject jsonObject = JObject.Parse(res);

            // 获取LoginResultType的值
            int loginResultType = (int)jsonObject["LoginResultType"];

            // 判断登录结果，如果为1表示登录成功
            if (loginResultType == 1)
            {


                // 登录成功，调用自定义接口
                HttpClient customHttpClient = new HttpClient();
                customHttpClient.Url = baseUrl + "DzInfo.TuiLing.WebApi.AutoReturnPicking.ToPicking,DzInfo.TuiLing.common.kdsvc";

                // 直接从parameterNode中获取参数值
                var customRequest = new
                {
                    parameter = new
                    {
                        K3Operation = parameterNode["K3Operation"]?.ToString() ?? "BillEdit",
                        K3TargetBillPkValue = parameterNode["K3TargetBillPkValue"] != null ?
                            Convert.ToInt64(parameterNode["K3TargetBillPkValue"]) : 100002,
                        K3SourceBillPkValue = parameterNode["K3SourceBillPkValue"] != null ?
                            Convert.ToInt64(parameterNode["K3SourceBillPkValue"]) : 100003,
                        K3UserName = userName,
                        ReturnerId = parameterNode["ReturnerId"]?.ToString(),
                        K3AppSecret = appsecret,
                        K3AppID = appid,
                        K3TargetFormId = parameterNode["K3TargetFormId"]?.ToString() ?? "PRD_PPBOM",
                        K3DBID = dbId,
                        FMemo = parameterNode["FMemo"]?.ToString() ?? "自动退领料",
                        FEntity = GetFEntityFromParameter(parameterNode)
                    }
                };

                // 直接序列化，不进行额外包装
                customHttpClient.Content = JsonConvert.SerializeObject(customRequest);

                var customResult = customHttpClient.SysncRequest();

                return new
                {
                    LoginSuccess = true,
                    CustomInterfaceResult = customResult,
                    Message = "登录成功并已调用自定义接口"
                };
            }
            else
            {
                // 登录失败，返回登录结果
                return new
                {
                    LoginSuccess = false,
                    LoginResultType = loginResultType,
                    Message = "金蝶系统登录失败",
                    OriginalResponse = res
                };
            }


        }

        private object GetFEntityFromParameter(JSONObject parameterNode)
        {
            if (parameterNode != null && parameterNode.ContainsKey("FEntity"))
            {
                try
                {
                    var fEntityValue = parameterNode["FEntity"];
                    if (fEntityValue is JSONArray)
                    {
                        return fEntityValue as JSONArray;
                    }
                    else if (fEntityValue is string && !string.IsNullOrEmpty(fEntityValue.ToString()))
                    {
                        return JSONArray.Parse(fEntityValue.ToString());
                    }
                }
                catch (Exception ex)
                {
                    //Logger.Error("AutoReturnPicking", $"解析FEntity失败: {ex.Message}");
                    // 解析失败，使用默认值
                }
            }

            // 使用默认的FEntity
            return new JSONArray
    {
        new JSONObject
        {
            ["FAuxPropID_CD"] = "930",
            ["FBaseQty"] = 2,
            ["FMaterial"] = "FZ02",
            ["FStockLOCID_KW"] = "A01",
            ["FLot"] = "248-002",
            ["FMESPickType"] = "自动退领",
            ["FEntityMemo"] = "",
            ["FUnit1"] = "Pcs",
            ["FAuxPropID_WJ"] = "",
            ["FSecQty"] = 1,
            ["FAuxPropID_CZ"] = "08",
            ["FUnit2"] = "Pcs",
            ["FAuxPropID_KD"] = "900",
            ["FAuxPropID_NJ"] = "",
            ["FStockID"] = "CK004"
        }
    };
        }

        /// <summary>
        /// 初始化参数
        /// </summary>
        /// <param name="meta"></param>
        /// <param name="ctx"></param>
        /// <returns></returns>
        public static BillOpenParameter CreateOpenParameter(FormMetadata meta, Context ctx)
        {
            Form form = meta.BusinessInfo.GetForm();
            BillOpenParameter openParam = new BillOpenParameter(form.Id, meta.GetLayoutInfo().Id);
            openParam.Context = ctx;
            openParam.ServiceName = form.FormServiceName;
            openParam.PageId = Guid.NewGuid().ToString();
            openParam.FormMetaData = meta;
            openParam.Status = OperationStatus.ADDNEW;
            openParam.PkValue = null;
            openParam.CreateFrom = CreateFrom.Default;
            openParam.GroupId = "";
            openParam.ParentId = 0;
            openParam.DefaultBillTypeId = "";
            openParam.DefaultBusinessFlowId = "";
            openParam.SetCustomParameter("ShowConfirmDialogWhenChangeOrg", false);
            List<AbstractDynamicFormPlugIn> plugs = form.CreateFormPlugIns();
            openParam.SetCustomParameter(FormConst.PlugIns, plugs);
            PreOpenFormEventArgs args = new PreOpenFormEventArgs(ctx, openParam);
            foreach (var plug in plugs)
            {
                plug.PreOpenForm(args);
            }
            if (args.Cancel == true)
            {
                // 不理会插件的诉求，继续....
            }
            return openParam;
        }
        /// <summary>
        /// 初始化视图
        /// </summary>
        /// <param name="ctx">上下文</param>
        /// <param name="formId">单据标识</param>
        /// <returns></returns>
        public static IBillView CreateView(Context ctx, string formId)
        {
            FormMetadata meta = MetaDataServiceHelper.Load(ctx, formId) as FormMetadata;
            Form form = meta.BusinessInfo.GetForm();
            Type type = Type.GetType("Kingdee.BOS.Web.Import.ImportBillView,Kingdee.BOS.Web");
            var billView = (IDynamicFormViewService)Activator.CreateInstance(type);
            BillOpenParameter openParam = CreateOpenParameter(meta, ctx);
            var provider = form.GetFormServiceProvider();
            billView.Initialize(openParam, provider);
            return billView as IBillView;
        }
        public string ToPicking(string parameter)
        {
            var ctx = KDContext.Session.AppContext;
            if (ctx == null)
            {
                // 会话超时，需重新登录
                throw new Exception("ctx = null,会话超时，需重新登录");
            }
            string resStr = "";
            try
            {
                // 1. 参数验证
                if (string.IsNullOrEmpty(parameter))
                {
                    return "请求参数不能为空";
                }

                // 2. 解析JSON参数
                JSONObject requestData;
                try
                {
                    requestData = JSONObject.Parse(parameter) as JSONObject;
                }
                catch (Exception ex)
                {
                    return $"JSON解析失败: {ex.Message}";
                }

                // 3. 安全获取参数节点
                JSONObject parameterNode = null;

                // 方法1: 使用ContainsKey检查
                if (requestData.ContainsKey("parameter"))
                {
                    var parameterValue = requestData["parameter"];
                    if (parameterValue is JSONObject)
                    {
                        parameterNode = parameterValue as JSONObject;
                    }
                    else
                    {
                        //Logger.Error("AutoReturnPicking", $"parameter节点类型不正确，期望JSONObject，实际为: {parameterValue?.GetType()}");
                        return "parameter参数格式不正确，应为对象类型";
                    }
                }

                // 4. 提取基础参数
                var operation = requestData["K3Operation"]?.ToString();
                var targetBillPkValue = requestData["K3TargetBillPkValue"]?.ToString();
                string tarPPbomId = GetPPbomId(targetBillPkValue, ctx);
                var sourceBillPkValue = requestData["K3SourceBillPkValue"]?.ToString();
                string souPPbomId = GetPPbomId(sourceBillPkValue, ctx);
                var userName = requestData["K3UserName"]?.ToString();
                var appSecret = requestData["K3AppSecret"]?.ToString();
                var appId = requestData["K3AppID"]?.ToString();
                var targetFormId = requestData["K3TargetFormId"]?.ToString();
                var dbId = requestData["K3DBID"]?.ToString();
                var memo = requestData["FMemo"]?.ToString();
                var ReturnerNumber = requestData["ReturnerId"]?.ToString();
                if (ReturnerNumber.IsNullOrEmptyOrWhiteSpace())
                {
                    return "ReturnerId参数格式不正确，应为退料人员工编码";
                }
                int ReturnerId = GetReturnerId(ReturnerNumber, ctx);
                //明细数据
                var entityArray = requestData["FEntity"] as JSONArray;
                if (entityArray == null || entityArray.Count == 0)
                {
                    return "缺少必要参数FEntity行明细数据为空";
                }
                //检查仓库启用的仓位情况
                foreach (JSONObject row in entityArray)
                {
                    string FStockID = row["FStockID"]?.ToString();
                    DynamicObjectCollection stockFlex = GetStockFlex(ctx, FStockID);
                }

                // 5. 验证必要参数
                if (string.IsNullOrEmpty(targetBillPkValue) || string.IsNullOrEmpty(sourceBillPkValue))
                {
                    return "缺少必要参数: K3TargetBillPkValue 或 K3SourceBillPkValue";
                }

                // 6. 加载原生产用料清单，并添加参数明细行的数据为返还件行
                IBillView billView = CreateView(ctx, "PRD_PPBOM");
                ((IBillViewService)billView).LoadData();
                DynamicFormViewPlugInProxy eventProxy = billView.GetService<DynamicFormViewPlugInProxy>();
                eventProxy.FireOnLoad();
                billView.Model.Load(souPPbomId);
                billView.Model.ClearNoDataRow();
                // 获取单据体实体
                EntryEntity entity = billView.BillBusinessInfo.GetEntryEntity("FEntity");
                var entityData = billView.Model.GetEntityDataObject(entity);
                var oldRows = entityData.Select(s => Convert.ToInt64(s["id"])).ToList();
                int lastRowIndex = entityData.Count;
                if (entityArray.Count > 0)
                {
                    foreach (JSONObject rowObj in entityArray)
                    {
                        if (rowObj == null) continue;

                        // 获取单据体实体的动态对象类型
                        var entityType = entity.DynamicObjectType;
                        // 创建正确的动态对象
                        DynamicObject entityRow = new DynamicObject(entityType);
                        billView.Model.CreateNewEntryRow(entity, lastRowIndex, entityRow);
                        // 填充数据到新行对象
                        FillEntityRowData(entityRow, rowObj, lastRowIndex, billView, ctx);
                        // 行索引递增
                        lastRowIndex++;
                    }

                }
                //保存原生产用料清单
                resStr += OnlySaveBill(billView, OperateOption.Create(), ctx) + ";";
                // 关键修正：保存后重新加载数据获取真实ID
                billView.Model.Load(souPPbomId);
                entityData = billView.Model.GetEntityDataObject(entity);
                var newRows = entityData.Select(s => Convert.ToInt64(s["id"])).ToList();

                //下推生产退料单
                //var newRows = entityData.Where(w => Convert.ToInt32(w["MaterialType"]) == 2 && Convert.ToDecimal(w["NoPickedQty"]) < 0).Select(s => Convert.ToInt64(s["id"])).ToList();
                //var xtObjs = DzConvertService(ctx, "PRD_PPBOM", "PRD_ReturnMtrl", "FEntity", "", "", "", "", "");
                List<ConvertRuleElement> convertRules = ConvertServiceHelper.GetConvertRules(ctx, "PRD_PPBOM", "PRD_ReturnMtrl");
                var convertRule = convertRules.Find(f => f.Id.Equals("PRD_PPBOM2RETURNMTRL"));
                //构建下推行数据
                List<ListSelectedRow> selectedRows = new List<ListSelectedRow>();
                foreach (var row in newRows)
                {
                    Dictionary<string, string> fieldValues = new Dictionary<string, string>();
                    fieldValues.Add("FEntity", row.ToString());
                    // 直接使用long类型的row作为entryPrimaryKeyValue，注意ListSelectedRow相关构造函数
                    var selectedRow = new ListSelectedRow(sourceBillPkValue, row.ToString(), 0, convertRule.SourceFormId)
                    {
                        EntryEntityKey = "FEntity",// 明确指定分录实体键
                        FieldValues = fieldValues
                    };

                    selectedRows.Add(selectedRow);

                }
                //构建参数

                PushArgs pushArgs = new PushArgs(convertRule, selectedRows.ToArray());

                OperateOption operateOption = OperateOption.Create();
                ConvertOperationResult operationResult = ConvertServiceHelper.Push(ctx, pushArgs, operateOption);

                var array = operationResult.TargetDataEntities.ToArray();
                List<DynamicObject> listTarObj = new List<DynamicObject>();
                foreach (var extData in array)
                {
                    DynamicObject dataEntity = extData.DataEntity;
                    listTarObj.Add(dataEntity);
                }
                //修改下推数据包，添加退料人
                foreach (var tlObj in listTarObj)
                {
                    FormMetadata meta3 = (FormMetadata)AppServiceContext.MetadataService.Load(ctx, "PRD_ReturnMtrl", true);
                    BaseDataField returnId = meta3.BusinessInfo.GetField("FReturnerId") as BaseDataField;
                    IViewService viewService = ServiceHelper.GetService<IViewService>();
                    DynamicObject[] stockObjs = viewService.LoadFromCache(ctx,
                        new object[] { ReturnerId },
                        returnId.RefFormDynamicObjectType);

                    returnId.RefIDDynamicProperty.SetValue(tlObj, ReturnerId);
                    returnId.DynamicProperty.SetValue(tlObj, stockObjs[0]);
                }
                FormMetadata meta = (FormMetadata)AppServiceContext.MetadataService.Load(ctx, "PRD_ReturnMtrl", true);
                OperateOption option = OperateOption.Create();
                var saveResult = AppServiceContext.SaveService.Save(ctx, meta.BusinessInfo, listTarObj.ToArray(), option, "");
                if (saveResult.IsSuccess)
                {
                    var pkArray = (from o in listTarObj
                                   select o["Id"]).ToArray();
                    saveResult.MergeResult(AppServiceContext.SubmitService.Submit(ctx, meta.BusinessInfo, pkArray, "Submit", null));
                    if (saveResult.IsSuccess)
                    {
                        saveResult.MergeResult(AppServiceContext.AuditService.Audit(ctx, meta.BusinessInfo, pkArray, OperateOption.Create()));
                    }
                }
                var saveMessage = saveResult.OperateResult.Select(s => s.Message).ToList();
                resStr += string.Join(";", saveMessage);
                //加载目标生产用料清单
                IBillView bv2 = CreateView(ctx, "PRD_PPBOM");
                ((IBillViewService)bv2).LoadData();
                DynamicFormViewPlugInProxy eventProxy2 = bv2.GetService<DynamicFormViewPlugInProxy>();
                eventProxy2.FireOnLoad();
                bv2.Model.Load(tarPPbomId);
                bv2.Model.ClearNoDataRow();
                // 获取单据体实体
                EntryEntity entity2 = bv2.BillBusinessInfo.GetEntryEntity("FEntity");
                var entityData2 = bv2.Model.GetEntityDataObject(entity2);
                var oldRowIds = entityData2.Select(s => Convert.ToInt64(s["id"])).ToList();
                int lastRowIndex2 = entityData2.Count;
                if (entityArray.Count > 0)
                {
                    foreach (JSONObject rowObj in entityArray)
                    {
                        if (rowObj == null) continue;

                        // 获取单据体实体的动态对象类型
                        var entityType = entity2.DynamicObjectType;
                        // 创建正确的动态对象
                        DynamicObject entityRow = new DynamicObject(entityType);
                        bv2.Model.CreateNewEntryRow(entity2, lastRowIndex2, entityRow);
                        // 填充数据到新行对象
                        FillEntityRowData2(rowObj, lastRowIndex2, bv2, ctx);
                        // 行索引递增
                        lastRowIndex2++;
                    }

                }
                //保存目标生产用料清单
                resStr += OnlySaveBill(bv2, OperateOption.Create(), ctx);

                // 关键修正：保存后重新加载数据获取真实ID
                bv2.Model.Load(tarPPbomId);
                entityData2 = bv2.Model.GetEntityDataObject(entity2);
                var newRowIds = entityData2.Select(s => Convert.ToInt64(s["id"])).ToList();
                //下推生产领料单
                // 获取新增行的ID集合 - 使用Except方法找出新增的ID
                var tarRows = newRowIds.Except(oldRowIds).ToList();
                //var xtObjs = DzConvertService(ctx, "PRD_PPBOM", "PRD_ReturnMtrl", "FEntity", "", "", "", "", "");
                List<ConvertRuleElement> convertRules2 = ConvertServiceHelper.GetConvertRules(ctx, "PRD_PPBOM", "PRD_PickMtrl");
                var convertRule2 = convertRules2.Find(f => f.Id.Equals("PRD_PPBOM2PICKMTRL_NORMAL"));
                //构建下推行数据
                List<ListSelectedRow> selectedRows2 = new List<ListSelectedRow>();
                foreach (var row in tarRows)
                {
                    Dictionary<string, string> fieldValues = new Dictionary<string, string>();
                    fieldValues.Add("FEntity", row.ToString());
                    // 直接使用long类型的row作为entryPrimaryKeyValue，注意ListSelectedRow相关构造函数
                    var selectedRow2 = new ListSelectedRow(targetBillPkValue, row.ToString(), 0, convertRule2.SourceFormId)
                    {
                        EntryEntityKey = "FEntity",// 明确指定分录实体键
                        FieldValues = fieldValues
                    };

                    selectedRows2.Add(selectedRow2);

                }
                //构建参数

                PushArgs pushArgs2 = new PushArgs(convertRule2, selectedRows2.ToArray())
                {
                    TargetBillTypeId = "f4f46eb78a7149b1b7e4de98586acb67"
                };

                OperateOption operateOption2 = OperateOption.Create();
                ConvertOperationResult operationResult2 = ConvertServiceHelper.Push(ctx, pushArgs2, operateOption2);
                var array2 = operationResult2.TargetDataEntities.ToArray();
                List<DynamicObject> listTarObj2 = new List<DynamicObject>();
                foreach (var extData in array2)
                {
                    DynamicObject dataEntity = extData.DataEntity;
                    listTarObj2.Add(dataEntity);
                }
                //修改下推数据包，添加领料人
                foreach (var llObj in listTarObj2)
                {
                    FormMetadata meta4 = (FormMetadata)AppServiceContext.MetadataService.Load(ctx, "PRD_PickMtrl", true);
                    BaseDataField returnId = meta4.BusinessInfo.GetField("FPickerId") as BaseDataField;
                    IViewService viewService = ServiceHelper.GetService<IViewService>();
                    DynamicObject[] stockObjs = viewService.LoadFromCache(ctx,
                        new object[] { ReturnerId },
                        returnId.RefFormDynamicObjectType);

                    returnId.RefIDDynamicProperty.SetValue(llObj, ReturnerId);
                    returnId.DynamicProperty.SetValue(llObj, stockObjs[0]);
                }
                FormMetadata meta2 = (FormMetadata)AppServiceContext.MetadataService.Load(ctx, "PRD_PickMtrl", true);
                OperateOption option2 = OperateOption.Create();
                var saveResult2 = AppServiceContext.SaveService.Save(ctx, meta2.BusinessInfo, listTarObj2.ToArray(), option2, "");
                if (saveResult2.IsSuccess)
                {
                    var pkArray = (from o in listTarObj2
                                   select o["Id"]).ToArray();
                    saveResult2.MergeResult(AppServiceContext.SubmitService.Submit(ctx, meta2.BusinessInfo, pkArray, "Submit", null));
                    if (saveResult2.IsSuccess)
                    {
                        saveResult2.MergeResult(AppServiceContext.AuditService.Audit(ctx, meta2.BusinessInfo, pkArray, OperateOption.Create()));
                    }
                }
                var tarMessage = saveResult2.OperateResult.Select(s => s.Message).ToList();
                resStr += string.Join(";", tarMessage);
            }
            catch (Exception ex)
            {
                // 记录异常日志
                //Logger.Error("AutoReturnPicking", $"系统异常:{ex.Message}", ex);
                return $"系统异常: {ex.Message}+;执行:{resStr}";
            }
            return resStr;
        }

        private DynamicObjectCollection GetStockFlex(Context ctx, string fStockID)
        {
            string sql = string.Format(@"/*dialect*/ 
            select t1.FFLEXID from t_BD_Stock t0
            join T_BD_STOCKFLEXITEM t1 on t1.FSTOCKID=t0.FSTOCKID
            where t0.FNUMBER='{0}' ", fStockID);
            DynamicObjectCollection doc = DBUtils.ExecuteDynamicObject(ctx, sql);
            return doc;
        }

        private int GetReturnerId(string returnerNumber, Context ctx)
        {
            string sql = string.Format(@"/*dialect*/ 
            select top 1 FSTAFFID from T_BD_STAFF where FNUMBER='{0}' ", returnerNumber);
            DynamicObjectCollection doc = DBUtils.ExecuteDynamicObject(ctx, sql);
            if (doc == null || doc.Count == 0)
            {
                return 0;
            }
            else
            {
                return Convert.ToInt32(doc[0][0]);
            }
        }

        private string GetPPbomId(string targetBillPkValue, Context ctx)
        {
            string sql = string.Format(@"/*dialect*/ 
            select FID from T_PRD_PPBOM where FMOENTRYID='{0}' ", targetBillPkValue);
            DynamicObjectCollection doc = DBUtils.ExecuteDynamicObject(ctx, sql);
            if (doc == null || doc.Count == 0)
            {
                return "0";
            }
            else
            {
                return doc[0][0].ToString();
            }
        }

        private string FillEntityRowData2(JSONObject rowData, int lastRowIndex, IBillView billView, Context ctx)
        {
            //生产组织
            var prdOrg = billView.Model.DataObject["PrdOrgId"] as DynamicObject;
            long prdOrgId = prdOrg == null ? 0 : Convert.ToInt64(prdOrg["id"]);
            var mainOrg = billView.BillBusinessInfo.MainOrgField.Key;
            //数量
            var qty = Convert.ToDecimal(billView.Model.DataObject["Qty"]);
            //仓位
            RelatedFlexGroupField stockLocField = billView.BusinessInfo.GetField("FStockLOCID") as RelatedFlexGroupField;
            //辅助属性
            RelatedFlexGroupField auxPropField = billView.BusinessInfo.GetField("FAuxPropID") as RelatedFlexGroupField;
            try
            {
                billView.Model.SetItemValueByNumber("FMaterialID2", rowData["FMaterial"]?.ToString(), lastRowIndex);
                billView.Model.SetItemValueByNumber("FUnitID2", rowData["FUnit1"]?.ToString(), lastRowIndex);
                billView.Model.SetValue("FMaterialType", 1, lastRowIndex);
                billView.Model.SetValue("FNumerator", rowData["FBaseQty"], lastRowIndex);
                billView.Model.SetValue("FDenominator", qty, lastRowIndex);
                billView.Model.SetItemValueByNumber("FStockID", rowData["FStockID"]?.ToString(), lastRowIndex);
                billView.Model.SetValue("FLot", rowData["FLot"], lastRowIndex);
                billView.Model.SetValue("FMEMO1", rowData["FMESPickType"], lastRowIndex);

                billView.Model.SetValue("FOwnerTypeId", "BD_OwnerOrg", lastRowIndex);
                billView.Model.SetItemValueByID("FOwnerID", prdOrgId, lastRowIndex);
                //填仓位
                DynamicObject dyRow = billView.Model.GetEntityDataObject(stockLocField.Entity)[lastRowIndex];
                // 清空仓位
                stockLocField.DynamicProperty.SetValue(dyRow, null);
                stockLocField.RefIDDynamicProperty.SetValue(dyRow, 0);
                int stockLocId = GetStockLocId(ctx, rowData["FStockLOCID_KW"].ToString());
                var stockLoc = BusinessDataServiceHelper.LoadFromCache(ctx, new object[] { stockLocId }, stockLocField.RefFormDynamicObjectType);
                if (stockLoc == null)
                {
                    return $"仓位:{rowData["FStockLOCID_KW"]}对应的ID{stockLocId}非法,请联系管理员！";
                }
                stockLocField.DynamicProperty.SetValue(dyRow, stockLoc[0]);
                stockLocField.RefIDDynamicProperty.SetValue(dyRow, stockLocId);
                //填辅助属性
                DynamicObject mat = dyRow["MaterialID"] as DynamicObject;
                long matId = mat == null ? 0 : Convert.ToInt64(mat["id"]);
                DynamicObjectCollection auxList = GetMatEnableAux(matId, ctx);
                if (auxList != null && auxList.Count > 0)
                {
                    foreach (var aux in auxList)
                    {
                        if (aux["FAUXPROPERTYID"].ToString() == "100001")
                        {
                            billView.Model.SetItemValueByNumber("$$FAUXPROPID__FF100001", rowData["FAuxPropID_CZ"].ToString(), lastRowIndex);
                        }
                        if (aux["FAUXPROPERTYID"].ToString() == "100002")
                        {
                            billView.Model.SetValue("$$FAUXPROPID__FF100002", rowData["FAuxPropID_CD"], lastRowIndex);
                        }
                        if (aux["FAUXPROPERTYID"].ToString() == "100003")
                        {
                            billView.Model.SetValue("$$FAUXPROPID__FF100003", rowData["FAuxPropID_KD"], lastRowIndex);
                        }
                        if (aux["FAUXPROPERTYID"].ToString() == "100009")
                        {
                            billView.Model.SetValue("$$FAUXPROPID__FF100009", rowData["FAuxPropID_WJ"], lastRowIndex);
                        }
                        if (aux["FAUXPROPERTYID"].ToString() == "100010")
                        {
                            billView.Model.SetValue("$$FAUXPROPID__FF100010", rowData["FAuxPropID_NJ"], lastRowIndex);
                        }
                        //
                        //if (aux["FAUXPROPERTYID"].ToString() == "100001")
                        //{
                        //    billView.Model.SetItemValueByNumber("$$FAUXPROPID__FF100001", rowData["FAuxPropID_CZ"].ToString(), lastRowIndex);
                        //}
                        //if (aux["FAUXPROPERTYID"].ToString() == "100002")
                        //{
                        //    billView.Model.SetValue("$$FAUXPROPID__FF100002", rowData["FAuxPropID_CD"], lastRowIndex);
                        //}
                        //if (aux["FAUXPROPERTYID"].ToString() == "100003")
                        //{
                        //    billView.Model.SetValue("$$FAUXPROPID__FF100003", rowData["FAuxPropID_KD"], lastRowIndex);
                        //}
                        //if (aux["FAUXPROPERTYID"].ToString() == "100004")
                        //{
                        //    billView.Model.SetValue("$$FAUXPROPID__FF100004", rowData["FAuxPropID_WJ"], lastRowIndex);
                        //}
                        //if (aux["FAUXPROPERTYID"].ToString() == "100005")
                        //{
                        //    billView.Model.SetValue("$$FAUXPROPID__FF100005", rowData["FAuxPropID_NJ"], lastRowIndex);
                        //}
                    }
                }
                return "";
            }
            catch (Exception ex)
            {
                //Logger.Error("AutoReturnPicking", $"填充明细行数据失败: {ex.Message}", ex);
                return ex.Message;
            }
        }

        /// <summary>
        /// 填充明细行数据
        /// </summary>
        private string FillEntityRowData(DynamicObject entityRow, JSONObject rowData, int lastRowIndex, IBillView billView, Context ctx)
        {
            //生产组织
            var prdOrg = billView.Model.DataObject["PrdOrgId"] as DynamicObject;
            long prdOrgId = prdOrg == null ? 0 : Convert.ToInt64(prdOrg["id"]);
            var mainOrg = billView.BillBusinessInfo.MainOrgField.Key;
            //数量
            var qty = Convert.ToDecimal(billView.Model.DataObject["Qty"]);
            //仓位
            RelatedFlexGroupField stockLocField = billView.BusinessInfo.GetField("FStockLOCID") as RelatedFlexGroupField;
            //辅助属性
            RelatedFlexGroupField auxPropField = billView.BusinessInfo.GetField("FAuxPropID") as RelatedFlexGroupField;
            try
            {
                billView.Model.SetItemValueByNumber("FMaterialID2", rowData["FMaterial"]?.ToString(), lastRowIndex);
                billView.Model.SetItemValueByNumber("FUnitID2", rowData["FUnit1"]?.ToString(), lastRowIndex);
                billView.Model.SetValue("FMaterialType", 2, lastRowIndex);
                billView.Model.SetValue("FNumerator", rowData["FBaseQty"], lastRowIndex);
                billView.Model.SetValue("FDenominator", qty, lastRowIndex);
                billView.Model.SetItemValueByNumber("FStockID", rowData["FStockID"]?.ToString(), lastRowIndex);
                billView.Model.SetValue("FLot", rowData["FLot"], lastRowIndex);
                billView.Model.SetValue("FMEMO1", rowData["FMESPickType"], lastRowIndex);

                billView.Model.SetValue("FOwnerTypeId", "BD_OwnerOrg", lastRowIndex);
                billView.Model.SetItemValueByID("FOwnerID", prdOrgId, lastRowIndex);
                //填仓位
                DynamicObject dyRow = billView.Model.GetEntityDataObject(stockLocField.Entity)[lastRowIndex];
                // 清空仓位
                stockLocField.DynamicProperty.SetValue(dyRow, null);
                stockLocField.RefIDDynamicProperty.SetValue(dyRow, 0);
                int stockLocId = GetStockLocId(ctx, rowData["FStockLOCID_KW"].ToString());
                var stockLoc = BusinessDataServiceHelper.LoadFromCache(ctx, new object[] { stockLocId }, stockLocField.RefFormDynamicObjectType);
                if (stockLoc == null)
                {
                    return $"仓位:{rowData["FStockLOCID_KW"]}对应的ID{stockLocId}非法,请联系管理员！";
                }
                stockLocField.DynamicProperty.SetValue(dyRow, stockLoc[0]);
                stockLocField.RefIDDynamicProperty.SetValue(dyRow, stockLocId);
                //填辅助属性
                DynamicObject mat = dyRow["MaterialID"] as DynamicObject;
                long matId = mat == null ? 0 : Convert.ToInt64(mat["id"]);
                DynamicObjectCollection auxList = GetMatEnableAux(matId, ctx);
                if (auxList != null && auxList.Count > 0)
                {
                    foreach (var aux in auxList)
                    {
                        if (aux["FAUXPROPERTYID"].ToString() == "100001")
                        {
                            billView.Model.SetItemValueByNumber("$$FAUXPROPID__FF100001", rowData["FAuxPropID_CZ"].ToString(), lastRowIndex);
                        }
                        if (aux["FAUXPROPERTYID"].ToString() == "100002")
                        {
                            billView.Model.SetValue("$$FAUXPROPID__FF100002", rowData["FAuxPropID_CD"], lastRowIndex);
                        }
                        if (aux["FAUXPROPERTYID"].ToString() == "100003")
                        {
                            billView.Model.SetValue("$$FAUXPROPID__FF100003", rowData["FAuxPropID_KD"], lastRowIndex);
                        }
                        if (aux["FAUXPROPERTYID"].ToString() == "100009")
                        {
                            billView.Model.SetValue("$$FAUXPROPID__FF100009", rowData["FAuxPropID_WJ"], lastRowIndex);
                        }
                        if (aux["FAUXPROPERTYID"].ToString() == "100010")
                        {
                            billView.Model.SetValue("$$FAUXPROPID__FF100010", rowData["FAuxPropID_NJ"], lastRowIndex);
                        }
                        //
                        //if (aux["FAUXPROPERTYID"].ToString() == "100001")
                        //{
                        //    billView.Model.SetItemValueByNumber("$$FAUXPROPID__FF100001", rowData["FAuxPropID_CZ"].ToString(), lastRowIndex);
                        //}
                        //if (aux["FAUXPROPERTYID"].ToString() == "100002")
                        //{
                        //    billView.Model.SetValue("$$FAUXPROPID__FF100002", rowData["FAuxPropID_CD"], lastRowIndex);
                        //}
                        //if (aux["FAUXPROPERTYID"].ToString() == "100003")
                        //{
                        //    billView.Model.SetValue("$$FAUXPROPID__FF100003", rowData["FAuxPropID_KD"], lastRowIndex);
                        //}
                        //if (aux["FAUXPROPERTYID"].ToString() == "100004")
                        //{
                        //    billView.Model.SetValue("$$FAUXPROPID__FF100004", rowData["FAuxPropID_WJ"], lastRowIndex);
                        //}
                        //if (aux["FAUXPROPERTYID"].ToString() == "100005")
                        //{
                        //    billView.Model.SetValue("$$FAUXPROPID__FF100005", rowData["FAuxPropID_NJ"], lastRowIndex);
                        //}
                    }
                }
                return "";
            }
            catch (Exception ex)
            {
                //Logger.Error("AutoReturnPicking", $"填充明细行数据失败: {ex.Message}", ex);
                return ex.Message;
            }
        }

        private DynamicObjectCollection GetMatEnableAux(long matId, Context ctx)
        {
            string sql = string.Format(@"/*dialect*/ 
            SELECT T1.FAUXPROPERTYID 
            FROM T_BD_MATERIAL T0
            JOIN t_BD_MaterialAuxPty T1 ON T1.FMATERIALID=T0.FMATERIALID
            WHERE T0.FMATERIALID={0} AND T1.FISENABLE=1 ", matId);
            DynamicObjectCollection doc = DBUtils.ExecuteDynamicObject(ctx, sql);
            return doc;
        }

        private int GetStockLocId(Context ctx, string cw)
        {
            string sql = string.Format(@"/*dialect*/ 
            SELECT top 1 T2.FID
            FROM T_BAS_FLEXVALUES T0
            JOIN T_BAS_FLEXVALUESENTRY T1 ON T1.FID=T0.FID
            JOIN T_BAS_FLEXVALUESDETAIL T2 ON T2.FF100007=T1.FENTRYID
            WHERE T0.FNUMBER='03' AND T1.FNUMBER='{0}' ", cw);
            //string sql = string.Format(@"/*dialect*/ 
            //SELECT T2.FID
            //FROM T_BAS_FLEXVALUES T0
            //JOIN T_BAS_FLEXVALUESENTRY T1 ON T1.FID=T0.FID
            //JOIN T_BAS_FLEXVALUESDETAIL T2 ON T2.FF100003=T1.FENTRYID
            //WHERE T0.FNUMBER='C' AND T1.FNUMBER='{0}' ", cw);
            DynamicObjectCollection doc = DBUtils.ExecuteDynamicObject(ctx, sql);
            if (doc == null || doc.Count == 0)
            {
                return 0;
            }
            else
            {
                return Convert.ToInt32(doc[0][0]);
            }
        }
        /// <summary>
        /// 下推服务
        /// </summary>
        /// <param name="ctx">上下文</param>
        /// <param name="sourceFormID">源单formId</param>
        /// <param name="targetFormID">目标单formId</param>
        /// <param name="entryEntityKey">单据体标识</param>
        /// <param name="billTypeID">源单单据类型</param>
        /// <param name="targetBillTypeId">目标单据类型</param>
        /// <param name="primaryKeyValue">源单FID</param>
        /// <param name="entryPrimaryKeyValue">源单分录</param>
        /// <param name="ruleStr">转换规则</param>
        /// <returns></returns>
        public static ConvertOperationResult DzConvertService(Context ctx, string sourceFormID, string targetFormID, string entryEntityKey, string billTypeID, string targetBillTypeId, string primaryKeyValue, string entryPrimaryKeyValue, string ruleStr)
        {
            List<ConvertRuleElement> convertRules = ConvertServiceHelper.GetConvertRules(ctx, sourceFormID, targetFormID);
            var convertRule = convertRules.Find(f => f.Id.Equals(ruleStr));
            List<ListSelectedRow> list2 = new List<ListSelectedRow>();
            Dictionary<string, string> fieldValues = new Dictionary<string, string>();
            fieldValues.Add(entryEntityKey, entryPrimaryKeyValue);
            list2.Add(new ListSelectedRow(primaryKeyValue, entryPrimaryKeyValue, 0, sourceFormID)
            {
                EntryEntityKey = entryEntityKey,
                FieldValues = fieldValues,
                BillTypeID = billTypeID
            });
            PushArgs serviceArgs = new PushArgs(convertRule, list2.ToArray())
            {
                TargetBillTypeId = targetBillTypeId
            };
            OperateOption operateOption = OperateOption.Create();
            //operateOption.SetVariableValue("TransInDetailId", num3);
            ConvertOperationResult operationResult = ConvertServiceHelper.Push(ctx, serviceArgs, operateOption);
            return operationResult;
        }

        private void SetStringField(DynamicObject entityRow, string fieldName, object value)
        {
            if (value != null && !string.IsNullOrEmpty(value.ToString()))
            {
                try
                {
                    entityRow[fieldName] = value.ToString();
                }
                catch (Exception ex)
                {
                    //Logger.Info($"设置字符串字段 {fieldName} 失败: {ex.Message}");
                }
            }
        }

        private void SetDecimalField(DynamicObject entityRow, string fieldName, object value)
        {
            if (value != null)
            {
                try
                {
                    if (decimal.TryParse(value.ToString(), out decimal decimalValue))
                    {
                        entityRow[fieldName] = decimalValue;
                    }
                }
                catch (Exception ex)
                {
                    //Logger.Info($"设置数值字段 {fieldName} 失败: {ex.Message}");
                }
            }
        }

        private void SetBaseDataField(DynamicObject entityRow, string fieldName, string number)
        {
            if (!string.IsNullOrEmpty(number))
            {
                try
                {
                    // 创建基础资料动态对象
                    //DynamicObject baseData = new DynamicObject();
                    //baseData["Number"] = number;
                    //entityRow[fieldName] = baseData;
                }
                catch (Exception ex)
                {
                    //Logger.Info($"设置基础资料字段 {fieldName} 失败: {ex.Message}");
                }
            }
        }

        private string OnlySaveBill(IBillView billView, OperateOption saveOption, Context ctx)
        {
            // 设置FormId
            Form form = billView.BillBusinessInfo.GetForm();
            if (form.FormIdDynamicProperty != null)
            {
                form.FormIdDynamicProperty.SetValue(billView.Model.DataObject, form.Id);
            }
            // 调用保存操作
            IOperationResult saveResult = BusinessDataServiceHelper.Save(
                        ctx,
                        billView.BillBusinessInfo,
                        billView.Model.DataObject,
                        saveOption,
                        "Save");
            // 显示处理结果
            if (saveResult == null)
            {
                return "未知原因导致保存失败！";
            }
            else if (saveResult.InteractionContext != null && saveResult.InteractionContext.Option.GetInteractionFlag().Count > 0)
            {
                return "保存原用料清单失败，需要用户确认问题:" + saveResult.InteractionContext.SimpleMessage;
            }
            return string.Join(";", saveResult.OperateResult.Select(s => s.Message).ToList());
        }
    }
}
